// #include <chrono>
#include <exception>
// #include <variant>
#include <coroutine>
#include "../co_async/steps/co_async/debug.hpp"

struct PreviousAwaiter {
    std::coroutine_handle<> mPrevious = nullptr;

    constexpr bool await_ready() const noexcept { return false; }

    constexpr std::coroutine_handle<> await_suspend(std::coroutine_handle<> coroutine) const noexcept {
        if(mPrevious){
            return mPrevious;
        }
        else{
            return std::noop_coroutine();
        }
    }

    constexpr void await_resume() const noexcept {}
};

template<class T>
struct Promise {
    auto initial_suspend() {
        return std::suspend_always();
    }

    auto final_suspend() noexcept {
        return PreviousAwaiter(mPrevious);
    }

    void unhandled_exception() {
        debug(), "unhandled_exception";
        
        mException = std::current_exception();
    }

    void return_value(T ret) {
        // mResult.template emplace<1>(ret);
        // std::construct_at(&mResult, std::move(ret));
        new (&mResult) T(std::move(ret));
    }

    auto yield_value(T ret) {
        // mResult.template emplace<1>(ret);
        // std::construct_at(&mResult, std::move(ret));
        new (&mResult) T(std::move(ret));
        return std::suspend_always();
    }

    // 返回引用，这样外面就可以将result移动出去。（而不是拷贝？）
    T result() {
        if (mException) [[unlikely]]{
            std::rethrow_exception(mException);
        }
        T ret = std::move(mResult);
        // std::destroy_at(&mResult);
        mResult.~T();
        return ret;
    }

    std::coroutine_handle<Promise> get_return_object() {
        return std::coroutine_handle<Promise>::from_promise(*this);
    }

    // 父调用者协程的句柄
    std::coroutine_handle<> mPrevious = nullptr;
    std::exception_ptr mException{};
    // 小寄巧：包一层union就不会初始化了。
    union {
        T mResult;
    };
    Promise() noexcept {}
    Promise(Promise &&) = delete;
    ~Promise() {}
};

template<>
struct Promise<void> {
    auto initial_suspend() {
        return std::suspend_always();
    }

    auto final_suspend() noexcept { 
        return PreviousAwaiter(mPrevious);
    }

    void unhandled_exception() {
        debug(), "unhandled_exception";
        mException = std::current_exception();
    }

    void return_void() {
    }

    // auto yield_value(T ret) {
    //     mResult.template emplace<1>(ret);
    //     return std::suspend_always();
    // }

    void result() {
        if(mException) [[unlikely]] {
            std::rethrow_exception(mException);
        }
    }

    std::coroutine_handle<Promise> get_return_object() {
        return std::coroutine_handle<Promise>::from_promise(*this);
    }

    // 父调用者协程的句柄
    std::coroutine_handle<> mPrevious = nullptr;

    // 返回值
    std::exception_ptr mException{};

    Promise() = default;
    Promise(Promise &&) = delete;
    ~Promise() = default;
};

template<class T>
struct Task{
    using promise_type = Promise<T>;

    Task(std::coroutine_handle<promise_type> coroutine)
        : mCoroutine(coroutine){}

    // 为什么说根据“三五法则”就要写这一行？移动构造？
    Task(Task &&) = delete;

    ~Task() {
        mCoroutine.destroy();
    }

    struct Awaiter{
        bool await_ready() const noexcept { return false; }

        std::coroutine_handle<> await_suspend(std::coroutine_handle<> coroutine) const noexcept {
            mCoroutine.promise().mPrevious = coroutine;

            return mCoroutine;
        }

        // 返回协程co_return的返回值值。
        T await_resume() const noexcept { return mCoroutine.promise().result(); }

        std::coroutine_handle<promise_type> mCoroutine;
    };

    auto operator co_await() {
        return Awaiter(mCoroutine);
    }

    std::coroutine_handle<promise_type> mCoroutine;
};

Task<double> world() {
    debug(), "world";
    co_return 3.14;
}

Task<std::string> baby() {
    debug(), "baby";
    co_return "aaa\n";
}

Task<int> hello() {
    auto ret = co_await baby();
    debug(), ret;
    int i = (int)co_await world();
    debug(), "i=", i;
    co_return i+1;
}

int main(){
    debug(), "main:  即将调用hello";
    Task t = hello();
    debug(), "main:  调用完了hello";
    while(!t.mCoroutine.done()){
        t.mCoroutine.resume();
        debug(), "main: main得到的hello结果为", t.mCoroutine.promise().result();
    }
    return 0;
}